package com.example.baseutils

import android.graphics.Bitmap
import android.graphics.Matrix
import android.renderscript.*
import com.example.baseutils.application.BaseApplication

/**
 * Author by lp,on 2022/1/15/015,11:27.
 */
object ImageUtils {
    private val rs: RenderScript = RenderScript.create(BaseApplication.instance.applicationContext)
    private val yuvToRgbIntrinsic: ScriptIntrinsicYuvToRGB =
        ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs))
    private var yuvType: Type.Builder? = null
    private var rgbaType: Type.Builder? = null
    private var `in`: Allocation? = null
    private var out: Allocation? = null

    private val originWith = Constance.CAMERA_WIDTH
    private val originHeight = Constance.CAMERA_HEIGHT
    private val clipWith = originHeight
    private val clipHeight = originHeight
    private val left = (originWith - clipWith) / 2

    private var bmpout:Bitmap?=null
    private var size=0
    //快速nv21转换bitmap方法
    //宽高必须符合数据格式，不可奇怪组合
    fun nv21ToBitmap(bytes: ByteArray?,isClip:Boolean): Bitmap? {
        var width=originWith
        var height: Int = originHeight
        if(bytes==null){
            return null
        }
        val nv21:ByteArray? = if(isClip){
            width=clipWith
            height=clipHeight
            clipNV21(bytes, originWith, originHeight, left, 0, width, height)
        }else{
            bytes
        }
        if (yuvType == null|| size!=nv21!!.size) {
            "yuvType create".log("DetectUtils")
            bmpout = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
            size=nv21!!.size
            yuvType = Type.Builder(rs, Element.U8(rs)).setX(size)
            `in` = Allocation.createTyped(rs, yuvType!!.create(), Allocation.USAGE_SCRIPT)
            rgbaType = Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height)
            out = Allocation.createTyped(rs, rgbaType!!.create(), Allocation.USAGE_SCRIPT)
        }
        `in`!!.copyFrom(nv21)
        yuvToRgbIntrinsic.setInput(`in`)
        yuvToRgbIntrinsic.forEach(out)
        out!!.copyTo(bmpout)
        return bmpout
    }

    //改变大小
    fun changeSize(bitmap: Bitmap, widths: Int, heghts: Int): Bitmap? {
        try {
            val width = bitmap.width
            val height = bitmap.height
            if (width == widths && height == heghts) {
                return bitmap
            }
            // 设置想要的大小
            // 计算缩放比例
            val scaleWidth = widths.toFloat() / width
            val scaleHeight = heghts.toFloat() / height
            val matrix = Matrix()
            matrix.postScale(scaleWidth, scaleHeight)
            return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    /**
     * NV21裁剪  算法效率 3ms
     *
     * @param src    源数据
     * @param width  源宽
     * @param height 源高
     * @param left   顶点坐标
     * @param top    顶点坐标
     * @param clip_w 裁剪后的宽
     * @param clip_h 裁剪后的高
     * @return 裁剪后的数据
     */
    fun clipNV21(
        src: ByteArray?,
        width: Int,
        height: Int,
        left: Int,
        top: Int,
        clip_w: Int,
        clip_h: Int
    ): ByteArray? {
        if (left > width || top > height || left + clip_w > width || top + clip_h > height) {
            "尺寸不规范".log("clipNV21")
            return null
        }
        //取偶
        val x = left / 4 * 4
        val y = top / 4 * 4
        val w = clip_w / 4 * 4
        val h = clip_h / 4 * 4
        val y_unit = w * h
        val uv = y_unit / 2
        val nData = ByteArray(y_unit + uv)
        val uv_index_dst = w * h - y / 2 * w
        val uv_index_src = width * height + x
        for (i in y until y + h) {
            System.arraycopy(src, i * width + x, nData, (i - y) * w, w) //y内存块复制
            if (i % 2 == 0) {
                System.arraycopy(
                    src,
                    uv_index_src + (i shr 1) * width,
                    nData,
                    uv_index_dst + (i shr 1) * w,
                    w
                ) //uv内存块复制
            }
        }
        return nData
    }

}